﻿using System;
using System.Collections.Generic;
using System.Drawing;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using SystemDiagramNew.Utils;

namespace SystemDiagramNew.TypeDefinition
{
	public class PipeInfo
	{
		public bool IsPipe { get; set; }

		public Element Component { get; set; }

		public XYZ StartPoint { get; set; }

		public XYZ EndPoint { get; set; }

		public int Diameter { get; set; }

		public int Width
		{
			get
			{
				return this.Diameter;
			}
			set
			{
				this.Diameter = value;
			}
		}

		public int Height { get; set; }

		public double StartElevation { get; set; }

		public double EndElevation { get; set; }

		public bool DrawingPipeLabel { get; set; }

		public LevelLabelPosition LevelLabelPosition { get; set; }

		public bool IsStandpipe()
		{
			return Geometry.IsEqual(this.StartPoint.X, this.EndPoint.X, 0.0001);
		}

		public bool IsEqual(PipeInfo rhs)
		{
			return this.Component != null && rhs.Component != null && this.Component.Id == rhs.Component.Id;
		}

		public bool IsLinked(PipeInfo rhs)
		{
			double eps = AssistFunc.mmToFeet(10.0);
			return Geometry.IsEqual(this.StartPoint, rhs.StartPoint, eps) || Geometry.IsEqual(this.StartPoint, rhs.EndPoint, eps) || Geometry.IsEqual(this.EndPoint, rhs.StartPoint, eps) || Geometry.IsEqual(this.EndPoint, rhs.EndPoint, eps);
		}

		public bool IsLinked(PipeInfo rhs, ref bool findStart)
		{
			double eps = AssistFunc.mmToFeet(10.0);
			if (Geometry.IsEqual(this.StartPoint, rhs.StartPoint, eps) || Geometry.IsEqual(this.StartPoint, rhs.EndPoint, eps))
			{
				findStart = true;
				return true;
			}
			if (Geometry.IsEqual(this.EndPoint, rhs.StartPoint, eps) || Geometry.IsEqual(this.EndPoint, rhs.StartPoint, eps))
			{
				findStart = false;
				return true;
			}
			return false;
		}

		public void AddSplitePoint(XYZ pt)
		{
			if (new XYZ(this.StartPoint.X, this.StartPoint.Y, 0.0).IsAlmostEqualTo(pt))
			{
				return;
			}
			if (new XYZ(this.EndPoint.X, this.EndPoint.Y, 0.0).IsAlmostEqualTo(pt))
			{
				return;
			}
			if (this.m_SplitPointList.FindIndex((XYZ s) => s.IsAlmostEqualTo(pt)) == -1)
			{
				this.m_SplitPointList.Add(pt);
			}
		}

		public List<XYZ> GetSplitLines()
		{
			List<XYZ> list = new List<XYZ>();
			foreach (XYZ xyz in this.m_SplitPointList)
			{
				list.Add(new XYZ(xyz.X, xyz.Y, 0.0));
			}
			list.Add(new XYZ(this.StartPoint.X, this.StartPoint.Y, 0.0));
			list.Add(new XYZ(this.EndPoint.X, this.EndPoint.Y, 0.0));
			list.Sort(new XYComparer());
			return list;
		}

		private TagPositionType TestPointPositionType(XYZ ptCurNodePos)
		{
			double val = this.StartPoint.DistanceTo(ptCurNodePos);
			double val2 = this.EndPoint.DistanceTo(ptCurNodePos);
			if (Geometry.LessThan(val, val2))
			{
				return TagPositionType.StartNode;
			}
			if (Geometry.GreaterThan(val, val2))
			{
				return TagPositionType.EndNode;
			}
			return TagPositionType.OtherPoint;
		}

		public bool GetAngle(XYZ ptCurNodePos, ref double curAngle)
		{
			TagPositionType tagPositionType = this.TestPointPositionType(ptCurNodePos);
			if (tagPositionType == TagPositionType.StartNode)
			{
				curAngle = Geometry.getAngle(new XYZ(this.StartPoint.X, this.StartPoint.Y, 0.0), new XYZ(this.EndPoint.X, this.EndPoint.Y, 0.0));
				return true;
			}
			if (tagPositionType == TagPositionType.EndNode)
			{
				curAngle = Geometry.getAngle(new XYZ(this.EndPoint.X, this.EndPoint.Y, 0.0), new XYZ(this.StartPoint.X, this.StartPoint.Y, 0.0));
				return true;
			}
			return false;
		}

		public XYZ CurStartPoint(XYZ ptCurNodePos)
		{
			TagPositionType tagPositionType = this.TestPointPositionType(ptCurNodePos);
			if (tagPositionType == TagPositionType.StartNode)
			{
				return this.StartPoint;
			}
			if (tagPositionType == TagPositionType.EndNode)
			{
				return this.EndPoint;
			}
			return null;
		}

		public void SetCurStartPoint(XYZ ptCurNodePos, XYZ newStart)
		{
			TagPositionType tagPositionType = this.TestPointPositionType(ptCurNodePos);
			if (tagPositionType == TagPositionType.StartNode)
			{
				this.StartPoint = newStart;
				return;
			}
			if (tagPositionType == TagPositionType.EndNode)
			{
				this.EndPoint = newStart;
			}
		}

		public XYZ CurEndPoint(XYZ ptCurNodePos)
		{
			TagPositionType tagPositionType = this.TestPointPositionType(ptCurNodePos);
			if (tagPositionType == TagPositionType.StartNode)
			{
				return this.EndPoint;
			}
			if (tagPositionType == TagPositionType.EndNode)
			{
				return this.StartPoint;
			}
			return null;
		}

		public void SetCurEndPoint(XYZ ptCurNodePos, XYZ newEnd)
		{
			TagPositionType tagPositionType = this.TestPointPositionType(ptCurNodePos);
			if (tagPositionType == TagPositionType.StartNode)
			{
				this.EndPoint = newEnd;
				return;
			}
			if (tagPositionType == TagPositionType.EndNode)
			{
				this.StartPoint = newEnd;
			}
		}

		public void Transform(Transform transform)
		{
			this.StartPoint = Geometry.TransformPoint(this.StartPoint, transform);
			this.EndPoint = Geometry.TransformPoint(this.EndPoint, transform);
		}

		public void TransformSplitPoints(Transform transform)
		{
			for (int i = 0; i < this.m_SplitPointList.Count; i++)
			{
				this.m_SplitPointList[i] = Geometry.TransformPoint(this.m_SplitPointList[i], transform);
			}
		}

		public void TransformSplitPointsToShaftSide(double angle)
		{
			for (int i = 0; i < this.m_SplitPointList.Count; i++)
			{
				this.m_SplitPointList[i] = Geometry.TransformPointToShaftSide(this.m_SplitPointList[i], angle);
			}
		}

		public static PipeInfo FromCurve(MEPCurve curve)
		{
			return PipeInfo.FromPipe(curve as Pipe) ?? PipeInfo.FromDuct(curve as Duct);
		}

		public static PipeInfo FromPipe(Pipe pipe)
		{
			if (pipe == null)
			{
				return null;
			}
			XYZ xyz;
			XYZ xyz2;
			if (!pipe.GetPoints(out xyz, out xyz2))
			{
				return null;
			}
			return new PipeInfo
			{
				IsPipe = true,
				Component = pipe,
				StartPoint = xyz,
				EndPoint = xyz2,
				Diameter = pipe.GetDiameter(),
				StartElevation = xyz.Z,
				EndElevation = xyz2.Z
			};
		}

		public static PipeInfo FromDuct(Duct pipe)
		{
			if (pipe == null)
			{
				return null;
			}
			XYZ xyz;
			XYZ xyz2;
			if (!pipe.GetPoints(out xyz, out xyz2))
			{
				return null;
			}
			Size size = pipe.GetSize();
			return new PipeInfo
			{
				IsPipe = false,
				Component = pipe,
				StartPoint = xyz,
				EndPoint = xyz2,
				Diameter = size.Width,
				Height = size.Height,
				StartElevation = xyz.Z,
				EndElevation = xyz2.Z
			};
		}

		internal static bool BLineReplace { get; set; }

		internal static ElementId LinePatternId { get; set; }

		internal static int LineWeight { get; set; }

        internal static Autodesk.Revit.DB.Color LineColor
        {
            get;
            set;
        }

		internal static Document CurDoc { get; set; }

		internal static ExternalCommandData Revit { get; set; }

		private static Document RvtDoc
		{
			get
			{
				return PipeInfo.Revit.Application.ActiveUIDocument.Document;
			}
		}

		internal Element Element
		{
			get
			{
				return this.Component;
			}
		}

		internal Pipe Pipe
		{
			get
			{
				return this.Element as Pipe;
			}
		}

		internal bool IsPipeOrDuct
		{
			get
			{
				return this.Element is Pipe || this.Element is Duct;
			}
		}

		internal DetailLine DrawLine(Autodesk.Revit.DB.View drawView)
		{
			DetailLine result;
			try
			{
				XYZ xy = this.StartPoint.GetXY();
				XYZ xy2 = this.EndPoint.GetXY();
				if (Geometry.IsEqual(xy, xy2))
				{
					result = null;
				}
				else
				{
					DetailCurve detailCurve = drawView.NewDetailLine(this.StartPoint.GetXY(), this.EndPoint.GetXY());
					DetailLine detailLine = detailCurve as DetailLine;
					if (PipeInfo.BLineReplace)
					{
						LineTypeOperate.SetLineStyleId(PipeInfo.RvtDoc, ref detailCurve);
					}
					ExtensibleStorageManager.WriteModelInfo(detailCurve, true, drawView.Id, this.Component.Id);
					result = detailLine;
				}
			}
			catch
			{
				result = null;
			}
			return result;
		}

		internal List<DetailLine> DrawSeparationLine(Autodesk.Revit.DB.View drawView)
		{
			List<DetailLine> result;
			try
			{
				List<DetailLine> list = new List<DetailLine>();
				List<XYZ> splitLines = this.GetSplitLines();
				XYZ xy = splitLines[0].GetXY();
				XYZ xyz = (splitLines[splitLines.Count - 1].GetXY() - xy).Normalize();
				XYZ xyz2 = xyz * 50.0.MMtoFeet();
				for (int i = 0; i < splitLines.Count - 1; i++)
				{
					XYZ xyz3 = splitLines[i].GetXY();
					XYZ xyz4 = splitLines[i + 1].GetXY();
					if (i != 0)
					{
						xyz3 += xyz2;
					}
					if (i != splitLines.Count - 2)
					{
						xyz4 -= xyz2;
					}
					if (!xyz3.IsAlmostEqualTo(xyz4) && (xyz4 - xyz3).Normalize().IsAlmostEqualTo(xyz))
					{
						DetailCurve detailCurve = drawView.NewDetailLine(xyz3.GetXY(), xyz4.GetXY());
						list.Add(detailCurve as DetailLine);
						if (PipeInfo.BLineReplace)
						{
							LineTypeOperate.SetLineStyleId(PipeInfo.RvtDoc, ref detailCurve);
						}
						ExtensibleStorageManager.WriteModelInfo(detailCurve, true, drawView.Id, this.Component.Id);
					}
				}
				result = list;
			}
			catch
			{
				result = null;
			}
			return result;
		}

		private readonly List<XYZ> m_SplitPointList = new List<XYZ>();
	}
}
